﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Windows.Media.Imaging;
using System.Windows.Media.Animation;

using Bling.Core;
using Bling.WPF;
using Bling.WPF.Util;
using Bling.Slides;
using Bling.Util;
using Bling.Shaders;
using Bling.Graphics;

namespace Bling.Example {
  using Bling.Matrices;
  using Bling.WPF3D;
  public class TextClip : Canvas {
    public class Row {
      public DoubleBl Top;
      public DoubleBl Height;
      public bool IsAlternate = false;
    }
    public class Column {
      public TextClip Container;
      public DoubleBl Left;
      public DoubleBl Width;
      public EnumBl<HorizontalAlignment> Alignment;
      public StringBl DefaultText;
      public PointBl LeftTopMargin {
        get {
          return new PointBl((this.Alignment == HorizontalAlignment.Left).
                   Condition(Container.Padding.X, 0), Container.Padding.Y);
        }
      }
      public PointBl SelfSize {
        get {
          return new PointBl(this.Width, Container.Field.Height + 2d * Container.Padding.Y);
        }
      }

      public PointBl SizeMargin {
        get {
          return SelfSize - LeftTopMargin -
            new PointBl((this.Alignment == HorizontalAlignment.Right).Condition(Container.Padding.X, 0), Container.Padding.Y);
        }
      }

    }
    public ColorBl PrimaryColor;
    public ColorBl AlternateColor;
    public FontCl Font = new FontCl() {
      Family = "Segoe UI".Convert<FontFamily>(),
      Brush = "#FF49627E".Convert<Color>(),
      Size = 12,
      Weight = FontWeights.Regular,
      Style = FontStyles.Normal,
    };
    public PointBl Padding = new PointBl(2d, 0d);

    public class Cell : Canvas {

      protected override void OnRender(DrawingContext dc) {
        base.OnRender(dc);
      }

      public Cell(Row Row, Column Column, TextClip Container) {
        var Self = this.Bl();
        Self.Left = Column.Left;
        Self.Top = Row.Top;
        //Self.LeftTop.Now = new PointBl(Column.Left, Row.Top);
        Self.Background.Now = Row.IsAlternate ? Container.AlternateColor : Container.PrimaryColor;

        var AlignClip = Self;
        if (false) {
          AlignClip = new CanvasBl(Self) {
            LeftTop = Column.LeftTopMargin,
            Size = Column.SizeMargin,
            ClipToBounds = { Now = true },
            Background = { Now = Brushes.Transparent },
          };
        } else {
          AlignClip.ClipToBounds.Now = true;
        }
        var Field = new TextBlockBl(AlignClip) {
          ZIndex = { Now = 0 },
          Background = { Now = Brushes.Transparent },
          Text = Column.DefaultText,
          Font = Container.Font,
          //Padding = new ThicknessBl(new PointBl(0, 0), new PointBl(0, 0)),
          Alignment = {
            Horizontal = { Now = HorizontalAlignment.Left, },
            Vertical = { Now = VerticalAlignment.Top, },
          },
        };
        Self.Size = new PointBl(Column.Width, Field.Height + 2d * Container.Padding.Y);
        Field.CenterPosition.Y = AlignClip.CenterSize.Y;
        DoubleBl LeftAlign = 0d;
        DoubleBl RightAlign = AlignClip.Width - Field.Width;
        DoubleBl CenterAlign = (AlignClip.Width / 2d) - (Field.Width / 2d); 
        Field.Left =
          (Column.Alignment == HorizontalAlignment.Left ).Condition(LeftAlign, 
          (Column.Alignment == HorizontalAlignment.Right).Condition(RightAlign, CenterAlign));

        BoolBl Ellided = Field.Width > AlignClip.Width;
        if (false) {
          { // right ellide.
            var R = new RectangleBl(Self) {
              Fill = Brushes.Black,
              ZIndex = 1,
              RightCenter = new PointBl(Self.Width, Self.Height / 2d),
              Size = new PointBl(1d, Self.Height - 2d),
              Visibility = Ellided & Column.Alignment != HorizontalAlignment.Right,
              Opacity = .35,
            };
            R = new RectangleBl(Self) {
              Fill = Brushes.Black,
              ZIndex = 1,
              RightCenter = R.LeftCenter,
              Size = new PointBl(1d, Self.Height),
              Visibility = Ellided & Column.Alignment != HorizontalAlignment.Right,
              Opacity = .18,
            };
            R = new RectangleBl(Self) {
              Fill = Brushes.Black,
              ZIndex = 1,
              RightCenter = R.LeftCenter,
              Size = new PointBl(1d, Self.Height),
              Visibility = Ellided & Column.Alignment != HorizontalAlignment.Right,
              Opacity = .08,
            };
          }
          { // left ellide.
            var R = new RectangleBl(Self) {
              Fill = Brushes.Black,
              ZIndex = 1,
              LeftCenter = new PointBl(0d, Self.Height / 2d),
              Size = new PointBl(1d, Self.Height - 2d),
              Visibility = Ellided & Column.Alignment != HorizontalAlignment.Left,
              Opacity = .35,
            };
            R = new RectangleBl(Self) {
              Fill = Brushes.Black,
              ZIndex = 1,
              LeftCenter = R.RightCenter,
              Size = new PointBl(1d, Self.Height),
              Visibility = Ellided & Column.Alignment != HorizontalAlignment.Left,
              Opacity = .18,
            };
            R = new RectangleBl(Self) {
              Fill = Brushes.Black,
              ZIndex = 1,
              LeftCenter = R.RightCenter,
              Size = new PointBl(1d, Self.Height),
              Visibility = Ellided & Column.Alignment != HorizontalAlignment.Left,
              Opacity = .08,
            };
          }
        }
      }
    }
    public struct ColorEntry {
      public string Name;
      public struct CS {
        public Color Primary;
        public Color Alternate;
      }
      public CS this[int n] {
        get {
          return n == 0 ? Light : n == 1 ? Medium : Heavy; 
        }
      }
      public CS Light;
      public CS Medium;
      public CS Heavy;
    }
    public static readonly List<ColorEntry> Colors = new List<ColorEntry>();

    private static void Add(string Name, 
      string PrimaryL, string AlternateL,
      string PrimaryM, string AlternateM,
      string PrimaryH, string AlternateH) {
      Colors.Add(new ColorEntry() {
        Name = Name,
        Light = new ColorEntry.CS() {
          Primary = PrimaryL.Convert<Color>(), 
          Alternate = AlternateL.Convert<Color>(),
        },
        Medium = new ColorEntry.CS() {
          Primary = PrimaryM.Convert<Color>(),
          Alternate = AlternateM.Convert<Color>(),
        },
        Heavy = new ColorEntry.CS() {
          Primary = PrimaryH.Convert<Color>(),
          Alternate = AlternateH.Convert<Color>(),
        },

      });
    }
    static TextClip() {
      Add("Indigo", "#E5EDF2", "#EDF2F6", "#DFE9F1", "#E9F0F5", "#DDE7EE", "#E8EEF3");
      Add("Dry Rose", "#F4E9EB", "#F7F0F1", "#F2E3E7", "#F6ECEE", "#ECDFE3", "#F2E9EC");
      Add("Gray Green", "#EAEEEC", "#F1F3F2", "#E3E9E7", "#ECF0EF", "#E0E4E3", "#EAEDEC");
      Add("Purple Lavender", "#F1E9F1", "#F6F0F6", "#EDE6EE", "#F3EEF3", "#E4E0E8", "#EDEAEF");
      Add("Forest Green", "#EFEFE8", "#F4F4EF", "#EAEAE2", "#F0F1EB", "#E5E5E0", "#EDEDE9");
      Add("Sandalwood Yellow", "#F4F0E6", "#F7F4EE", "#F1EBE1", "#F5F1EB", "#EEE6DE", "#F3EEE8");
      Add("Dry Orange", "#F5EBE7", "#F8F1EE", "#F5E5E2", "#F8EDEB", "#F0E2DF", "#F5EBE9");
    }
    public readonly Column[] Columns = new Column[20];
    public readonly Row[] Rows = new Row[30];
    private readonly LabelBl Field;

    public TextClip() {
      var Canvas = this.Bl();
      var ControlCanvas = new CanvasBl();
      var ControlWindow = new WindowBl() { Title = "Controls", Content = ControlCanvas, Width = 500d };

      LabelSliderBl First;
      FrameworkElementBl Current;
      LabelSliderBl FontSize = new LabelSliderBl(ControlCanvas) {
        Minimum = 8, Maximum = 20, LabelName = "Font Size", Value = 12,

      };
      First = FontSize;
      Current = First;

      var FontWeights0 = new FontWeight[] {
        FontWeights.Light, FontWeights.Normal, FontWeights.SemiBold, FontWeights.Bold, 
        FontWeights.ExtraBold, FontWeights.Heavy, FontWeights.ExtraBlack,
      };

      LabelSliderBl FontWeights1 = new LabelSliderBl(ControlCanvas) {
        Minimum = 0,
        Maximum = FontWeights0.Length - 1,
        LabelName = "Font Weight",
        Value = 1,
        LeftTop = Current.LeftBottom,
        Width = First.Width,
      };
      Current = FontWeights1;
      var FontWeight2 = FontWeights1.Value.Map<FontWeight, FontWeightBl>(d => FontWeights0[(int)Math.Round(d)]);


      LabelSliderBl HeightPad = new LabelSliderBl(ControlCanvas) {
        Minimum = 0,
        Maximum = 5,
        LabelName = "Height Pad",
        LeftTop = Current.LeftBottom,
        Width = First.Width,
      };
      Current = HeightPad;


      LabelSliderBl ColorSelect = new LabelSliderBl(ControlCanvas) {
        Minimum = 0,
        Maximum = Colors.Count - 1,
        LabelName = "Color Scheme",
        LeftTop = Current.LeftBottom,
        Width = First.Width,
      };
      Current = ColorSelect;
      LabelSliderBl ColorWeight = new LabelSliderBl(ControlCanvas) {
        Minimum = 0,
        Maximum = 3 - 1,
        LabelName = "Color Weight",
        LeftTop = Current.LeftBottom,
        Width = First.Width,
        Value = 2,
      };
      Current = ColorWeight;

      LabelSliderBl[] ColumnWidths = new LabelSliderBl[Columns.Length];
      TextBoxBl[] DefaultText0s = new TextBoxBl[Columns.Length];
      LabelSliderBl[] Alignments = new LabelSliderBl[Columns.Length];
      for (int i = 0; i < Columns.Length; i++) {
        var lbl = new LabelBl(ControlCanvas) { Content = "Clmn" + i, LeftTop = new PointBl(0, Current.Bottom), };
        ColumnWidths[i] = new LabelSliderBl(ControlCanvas) {
          Minimum = 50,
          Maximum = 200,
          LabelName = "Column Width",
          LeftTop = new PointBl(lbl.Width, Current.Bottom),
          Width = First.Width - lbl.Width,
        };
        Current = ColumnWidths[i];

        DefaultText0s[i] = new TextBoxBl(ControlCanvas) {
          LeftTop = new PointBl(lbl.Width, Current.Bottom),
          Width = First.Width - lbl.Width,
          Text = "Hello World",
        };
        Current = DefaultText0s[i];

        Alignments[i] = new LabelSliderBl(ControlCanvas) {
          Minimum = 0,
          Maximum = 3,
          LabelName = "Alignment",
          LeftTop = new PointBl(lbl.Width, Current.Bottom),
          Width = First.Width - lbl.Width,
          Value = i % 3.0,
        };
        Current = Alignments[i];
      }


      var ColorX = ColorSelect.Value.Combine(ColorWeight.Value);
      PrimaryColor = ColorX.Map<Vecs.Vec4<double>, ColorBl>((scheme, weight) => {
        var Cs = Colors[(int)Math.Round(scheme)][(int) Math.Round(weight)];
        return new Vecs.Vec4<double>() {
          X = Cs.Primary.ScR,
          Y = Cs.Primary.ScG,
          Z = Cs.Primary.ScB,
          W = Cs.Primary.ScA,
        };  
      });
      AlternateColor = ColorX.Map<Vecs.Vec4<double>, ColorBl>((scheme, weight) => {
        var Cs = Colors[(int)Math.Round(scheme)][(int)Math.Round(weight)];
        return new Vecs.Vec4<double>() {
          X = Cs.Alternate.ScR,
          Y = Cs.Alternate.ScG,
          Z = Cs.Alternate.ScB,
          W = Cs.Alternate.ScA,
        };
      });
      this.Background = Brushes.Gray;
      this.Padding = new PointBl(this.Padding.X, HeightPad);
      this.Font.Size = FontSize;
      this.Font.Weight = FontWeight2;

      var Canvas0 = new CanvasBl(Canvas) { Background = Brushes.White, Width = Canvas.Width, LeftTop = 0d };
      var Table = new CanvasBl(Canvas0) { Background = Brushes.White, CenterPosition = Canvas0.CenterSize };
      Canvas0.Height = Table.Height + 00d;
      {
        DoubleBl Left = 10d;
        for (int i = 0; i < Columns.Length; i++) {
          Columns[i] = new Column() {
            Alignment = Alignments[i].Value.Map<HorizontalAlignment, EnumBl<HorizontalAlignment>>(
              j => (j < 1) ? HorizontalAlignment.Left : 
                   (j < 2) ? HorizontalAlignment.Center : HorizontalAlignment.Right),

            //Alignment = (i == 0) ? HorizontalAlignment.Left : 
            //  (i == 1) ? HorizontalAlignment.Center : HorizontalAlignment.Right,
            Width = ColumnWidths[i], Left = Left,
            DefaultText = DefaultText0s[i].Text,

          };
          Left = Left + Columns[i].Width + 1d;
        }
        Left += 9d;
        Table.Width = Left;
      }
      {
        this.Field = new LabelBl(Canvas) { Content = DefaultText0s[0].Text, Font = Font, Padding = 0d, Visibility = false, };
        var RowHeight = Field.Height + 2d * Padding.Y;

        DoubleBl Top = 0d;
        for (int i = 0; i < Rows.Length; i++) {
          Rows[i] = new Row() {
            Height = RowHeight,
            Top = Top,
            IsAlternate = (i % 2) != 0,
          };
          Top = Top + Rows[i].Height + 1d;
        }
        Table.Height = Top;
      }
      for (int i = 0; i < Columns.Length; i++) {
        for (int j = 0; j < Rows.Length; j++) {
          var cell = new Cell(Rows[j], Columns[i], this);
          cell.Bl().CanvasParent = Table;
        }
      }
      //Table.CenterPosition = Canvas.CenterSize;
      First.LeftTop = new PointBl(0, 0);
      First.Width = ControlCanvas.Width;
      ControlCanvas.Height = Current.Bottom;
      foreach (var d in DefaultText0s) 
        d.Font = Font;
      ControlWindow.CurrentValue.Show();
    }
  }
}
